import ILinkedList from "../types/ILinkedList";
import { Node } from "./LinkedNode";

export class LinkedList<T> implements ILinkedList<T> {
  protected head: Node<T> | null = null;
  protected size: number = 0;

  protected tail: Node<T> | null = null;

  protected _getNode(position: number): Node<T> | null {
    let index = 0;
    let current = this.head;
    while (index++ < position && current) {
      current = current.next;
    }
    return current;
  }

  // 判断是否是尾节点
  private isTail(node: Node<T>) {
    return this.tail === node;
  }

  append(value: T): void {
    const newNode = new Node<T>(value);
    if (!this.head) {
      this.head = newNode;
    } else {
      this.tail!.next = newNode;
    }
    this.tail = newNode;

    this.size++;
  }

  insert(value: T, position: number): boolean {
    if (position < 0 || position > this.size) return false;
    const newNode = new Node<T>(value);
    if (position === 0) {
      newNode.next = this.head;
      this.head = newNode;
    } else {
      const previous = this._getNode(position - 1);
      newNode.next = previous!.next;
      previous!.next = newNode;
    }
    this.size++;
    return true;
  }
  get(position: number): T | null {
    if (position < 0 || position >= this.size) return null;
    return this._getNode(position)?.value ?? null;
  }

  removeAt(position: number): T | null {
    if (position < 0 || position >= this.size) return null;
    let current = this.head;
    if (position === 0) {
      this.head = current?.next || null;

      // 如果链表只有一个节点，需要将tail置为null,否则有指针指着,无法删除节点
      if (this.size === 1) {
        this.tail = null;
      }
    } else {
      // 重构代码
      const previousNode = this._getNode(position - 1);

      // 需要给current重新赋值
      current = previousNode!.next;

      // 找到需要的节点
      previousNode!.next = previousNode?.next?.next ?? null;

      // 如果删除的是最后一个节点
      if (position === this.size - 1) {
        this.tail = previousNode;
      }
    }
    this.size--;
    return current?.value ?? null;
  }
  traverse() {
    let current = this.head;

    let arr: T[] = [];
    while (current) {
      arr.push(current.value);
      if (this.isTail(current)) {
        current = null;
      } else {
        current = current.next;
      }
    }
    if (this.head && this.tail?.next === this.head) {
      arr.push(this.head?.value!);
    }
    const arrStr = arr.join("->");
    console.log(arrStr);

    return arrStr;
  }
  update(value: T, position: number): boolean {
    if (!this.size) return false;
    const currentNode = this._getNode(position);
    if (!currentNode) return false;
    currentNode.value = value;
    return true;
  }
  remove(value: T): T | null {
    const index = this.indexOf(value);
    return this.removeAt(index);
  }
  indexOf(value: any): number {
    if (!this.size) return -1;
    let current = this.head;
    let index = 0;
    while (index < this.size && current) {
      if (current.value === value) return index;
      if (this.isTail(current)) {
        current = null;
      } else {
        current = current.next;
        index++;
      }
    }
    return -1;
  }
  isEmpty(): boolean {
    return this.size === 0;
  }
  get length(): number {
    return this.size;
  }
}

// const linkedList = new LinkedList<string>();

// linkedList.append("a");
// linkedList.append("b");
// linkedList.append("c");
// linkedList.removeAt(2);
// linkedList.insert("x", 0);
// console.log(linkedList.insert("x", 2));

// linkedList.traverse();
// console.log(linkedList.get(3));
// console.log(linkedList.update("y", 1));
// linkedList.remove("y");
// linkedList.traverse();
// console.log(linkedList.indexOf("b"));
